Chart.js是一款open source的圖表製作library,支援多種圖表,包括Pie chart、Bar chart、line chart...等等,也有動畫效果,可以製作出精美的報表。
今天我們要建立一個Blazor WebAssembly專案,這個專案會串接一個新冠肺炎的Api,並使用Chart.js呈現近60天的確診人數折線圖,那我們就開始吧!
接下來主要分3部分進行:
Api部份,我們可以用https://covid19api.com/ 這個網站的Api來取得資料,一般資料是free的,如果有更多資料的需求再訂閱付費,我們可以到他的文件看一下有哪些Api可用。
首先建立Blazor WebAssembly專案,取消勾選Asp.net core hosted
建立完專案後,新增Service和Model資料夾,Model中加入json要對應的類別,Service資料夾加入COVID19Service。
COVID19Service有兩個方法:
GetCountriesAsync:取得index.razor的國家下拉選單資料
GetCountrySummaryAsync:傳入CountryCode,取得某國的確診、死亡等等人數
public class COVID19Service : ICOVID19Service
{
private readonly HttpClient httpClient;
private string baseurl { get; set; } = "https://api.covid19api.com";
public COVID19Service(HttpClient httpClient)
{
this.httpClient = httpClient;
}
/// <summary>
/// 取得國家清單
/// </summary>
/// <returns></returns>
public async Task<List<CountryModel>> GetCountriesAsync()
{
List<CountryModel> countries = new List<CountryModel>();
var response = await httpClient.GetAsync($"{baseurl}/countries");
if (response.IsSuccessStatusCode)
{
var contentString = await response.Content.ReadAsStringAsync();
countries = JsonConvert.DeserializeObject<List<CountryModel>>(contentString);
}
return countries;
}
/// <summary>
/// 取得確診、死亡等等人數資料
/// </summary>
/// <param name="countryCode"></param>
/// <returns></returns>
public async Task<List<CountrySummary>> GetCountrySummaryAsync(string countryCode)
{
List<CountrySummary> countrySummary = new List<CountrySummary>();
var respones = await httpClient.GetAsync($"{baseurl}/country/{countryCode}");
if (respones.IsSuccessStatusCode)
{
var contentString = await respones.Content.ReadAsStringAsync();
countrySummary = JsonConvert.DeserializeObject<List<CountrySummary>>(contentString);
}
return countrySummary.TakeLast(60).ToList();
}
}
在Program.cs註冊COVID19Service
builder.Services.AddScoped<ICOVID19Service, COVID19Service>();
使用cdn引入chart.js。可從https://cdnjs.com/libraries/Chart.js 取得cdn連結
再來把cdn script拉進wwwroot/index.html
<!DOCTYPE html>
<html>
//略....
<body>
<app>Loading...</app>
<div id="blazor-error-ui">
An unhandled error has occurred.
<a href="" class="reload">Reload</a>
<a class="dismiss">?</a>
</div>
<script src="_framework/blazor.webassembly.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<script src="script/MyChart.js"></script>
</body>
</html>
另外還拉了一個MyChart.js進去,這是我們自己建立的js檔,待會會在裡面寫產生圖表的程式碼
接下來到index.razor,這邊增加一個canvas標籤,產生的圖表會放到這個canvas內
<canvas id="myChart" width="800" height="300"></canvas>
在MyChart.js建立圖表資料
function DrawLineChart(summaryListlist) {
//建立圖表資料
var datachart = {
labels: [],
datasets: [{
label: '確診人數',
data: [],
borderColor: '#FF5376',
fill: false
}]
};
//將日期與人數push到labels和data陣列中
for (var i = 0; i < summaryListlist.length; i++) {
datachart.labels.push(summaryListlist[i].shortDate);
datachart.datasets[0].data.push(summaryListlist[i].confirmed);
}
//繪製圖表
var ctx = document.getElementById("myChart").getContext("2d");
var chart = new Chart(ctx, {
type: 'line', //圖表類型
data: datachart,
})
}
chart.js的官方文件還有許多設定可以套用,讓我們的圖表可以更美觀更友善
在畫面上會準備一個國家的下拉選單給user選取要看哪一國的資料,所以下拉選單部分會透過上述建立的COVID19Service取的國家資料後在塞到Select標籤中
@page "/"
@inject ICOVID19Service COVID19Service
<h2>COVID19 Chart</h2>
<hr />
@if (countries != null)
{
<div class="form-group">
<label for="countrySelect" class="font-weight-bold">國家</label>
<select @onchange="ChangeCountryAsync" class="form-control" id="countrySelect">
<option>--請選擇--</option>
@foreach (var item in countries)
{
<option value="@item.Slug" selected="@(item.Slug == DefaultCountry)">@item.Country</option>
}
</select>
</div>
//顯示chart的canvas標籤
<canvas id="myChart" width="800" height="300"></canvas>
}
else
{
//還在讀取資料時,顯示loading gif
<img src="https://media.giphy.com/media/3oEjI6SIIHBdRxXI40/giphy.gif" />
}
@code{
public string DefaultCountry { get; set; } = "taiwan";
public List<CountryModel> countries;
protected override async Task OnInitializedAsync()
{
countries = await COVID19Service.GetCountriesAsync();
}
}
在一進入index.razor,我希望顯示的是台灣的確診資料,因此在OnInitializedAsync方法取得下拉選單然後用一個預設為taiwan的DefaultCountry屬性,讓下拉選單預設選到taiwan
傳入countryCode取確診資料並透過IJSRuntime物件繪製圖表
@inject IJSRuntime js
@code{
private async Task BuildChartAsync(string selectedValue)
{
summaryList = await COVID19Service.GetCountrySummaryAsync(selectedValue);
summaryList.ForEach(x => x.ShortDate = $"{x.Date.Month}/{x.Date.Day}");
await js.InvokeVoidAsync("DrawLineChart", summaryList);
}
}
在OnInitializedAsync也加入BuildChartAsync
protected override async Task OnInitializedAsync()
{
countries = await COVID19Service.GetCountriesAsync();
BuildChartAsync(DefaultCountry);
}
選取國家時,處理onchange事件的ChangeCountryAsync方法中,使用ChangeEventArgs參數取得選擇的value,在傳入剛剛建立的BuildChartAsync方法
public async Task ChangeCountryAsync(ChangeEventArgs e)
{
if (e.Value != null)
{
await BuildChartAsync(e.Value.ToString());
}
}
最後完成的結果
程式碼可參考:https://github.com/CircleLin/COVID19_Chart
向您請教一下,我下載這個範例程式碼,我搜尋了5.6次後,再次搜尋他會把我前面搜尋過的結果圖表,全部都在跑一次,是什麼地方造成的錯誤嗎?